package com.shopping_back.serviceImpl;

import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shopping_back.common.SecurityUtils;
import com.shopping_back.pojo.dto.PageDTO;
import com.shopping_back.pojo.entity.UserAccount;
import com.shopping_back.mapper.UserAccountMapper;
import com.shopping_back.service.CaptchaService;
import com.shopping_back.service.IUserAccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * <p>
 * 用户账户表 服务实现类
 * </p>
 *
 * @author Jack
 * @since 2025-07-12
 */
@Service
@RequiredArgsConstructor
public class UserAccountServiceImpl extends ServiceImpl<UserAccountMapper, UserAccount> implements IUserAccountService {
    @Resource
    private CaptchaService captchaService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public boolean register(UserAccount user, String emailCaptcha) {
        // 1. 校验验证码
        String redisKey = "captcha:email:" + user.getEmail();
        String storedCaptcha = (String) stringRedisTemplate.boundHashOps(redisKey).get("captcha");

        if (StringUtils.isBlank(storedCaptcha) || !storedCaptcha.equals(emailCaptcha)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 2. 校验账号唯一性（邮箱/手机）
        if (count(new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getEmail, user.getEmail())
                .or()
                .eq(UserAccount::getMobile, user.getMobile())) > 0) {
            throw new RuntimeException("账号已存在");
        }

        // 3. 密码加密（SHA256 + 盐值）
        String salt = RandomStringUtils.randomAlphanumeric(16);
        String passwordHash = SecurityUtils.sha256Encrypt(user.getPasswordHash(), salt);

        // 4. 保存用户
        boolean success = save(user);

        // 5. 注册成功后清除验证码
        if (success) {
            stringRedisTemplate.delete(redisKey);
        }

        return success;
    }

    private final UserAccountMapper userAccountMapper;

    @Override
    @Transactional
    public void deleteAccount(Long id) {
        // 检查用户是否存在
        UserAccount user = userAccountMapper.selectById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }
        // 检查账号是否已注销
        if (!user.getStatus()) {
            throw new RuntimeException("账号已注销");
        }
        // 更新状态为已注销
        LambdaUpdateWrapper<UserAccount> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(UserAccount::getId, id)
                .set(UserAccount::getStatus, 0);
        int rows = userAccountMapper.update(null, updateWrapper);
        if (rows == 0) {
            throw new RuntimeException("注销账号失败");
        }
    }

    @Override
    public void resetPassword(Long id, String password, String repassword) {

        // 验证参数
        if (id == null || StringUtils.isBlank(password) || StringUtils.isBlank(repassword)) {
            throw new IllegalArgumentException("参数不能为空");
        }

        // 检查用户是否存在
        UserAccount user = userAccountMapper.selectById(id);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 验证旧密码
        String storedHash = user.getPasswordHash();
        String storedSalt = user.getSalt();
        if (StringUtils.isBlank(storedHash) || StringUtils.isBlank(storedSalt)) {
            throw new RuntimeException("用户密码数据异常");
        }
        String inputHash = SecurityUtils.sha256Encrypt(password, storedSalt);
        if (!inputHash.equals(storedHash)) {
            throw new RuntimeException("旧密码不正确");
        }

        // 验证新密码
        if (repassword.length() < 6) {
            throw new RuntimeException("新密码长度必须至少6位");
        }

        // 生成新盐值和密码哈希
        String newSalt = RandomStringUtils.randomAlphanumeric(16);
        String newPasswordHash = SecurityUtils.sha256Encrypt(repassword, newSalt);

        // 更新密码和盐值
        user.setPasswordHash(newPasswordHash);
        user.setSalt(newSalt);
        int rows = userAccountMapper.updateById(user);
        if (rows == 0) {
            throw new RuntimeException("重置密码失败");
        }
    }
    @Override
    public boolean existsByUsername(String username) {
        return count(new QueryWrapper<UserAccount>().eq("username", username)) > 0;
    }

    @Override
    public boolean existsByEmail(String email) {
        return count(new QueryWrapper<UserAccount>().eq("email", email)) > 0;
    }

    @Override
    public PageDTO<UserAccount> listAll(Integer pageNum, Integer pageSize, Integer status, String keyword) {
        Page<UserAccount> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<UserAccount> qw = new LambdaQueryWrapper<>();
        if (status != null) {
            qw.eq(UserAccount::getStatus, status);
        }
        if (keyword != null && !keyword.isBlank()) {
            String kw = keyword.trim();
            qw.like(UserAccount::getUsername, kw)
                    .or().like(UserAccount::getMobile, kw)
                    .or().like(UserAccount::getEmail, kw);
        }
        qw.orderByDesc(UserAccount::getCreateTime);

        Page<UserAccount> mpPage = this.page(page, qw);

        PageDTO<UserAccount> dto = new PageDTO<>();
        dto.setList(mpPage.getRecords());
        dto.setTotal(mpPage.getTotal());
        dto.setCurrentPage((int) mpPage.getCurrent());
        dto.setPageSize((int) mpPage.getSize());
        return dto;
    }

    @Override
    public void changeStatus(Long id, Boolean status) {
        UserAccount user = this.getById(id);
        if (user == null) throw new RuntimeException("用户不存在");
        if (user.getStatus() != status) {
            user.setStatus(status);
            this.updateById(user);
        }
    }
}
